/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

//#ifndef TRIANGLEGEOMETRY
//#define TRIANGLEGEOMETRY

#include <向量.h>
#include <矩阵.h>
//#include <Vector/向量运算.h>
#include <list>


typedef struct {
	vec3 pointA;
	vec3 pointB;
	vec3 pointC;
}S_三角形_;

typedef struct {
	vec2 pointA;
	vec2 pointB;
	vec2 pointC;
}S_2D三角形面顶点;

enum class E_PathType2D  {
	OuterRing,  // 外圈
	Hole        // 孔
};


//struct S_2D路径点 {
//	uint32 pointID;
//	std::list<S_2D路径>::iterator 前一个点;
//	std::list<S_2D路径>::iterator 后一个点;
//};

struct S_2D路径顶点索引 {
	uint32 p;
	uint32 层;
	uint64 idName;

	bool operator<(const S_2D路径顶点索引& other) const {
		if (p < other.p) {
			return 层 < other.层;
		}
		return false;
	}
	bool operator>(const S_2D路径顶点索引& other) const {
		if (p > other.p) {
			return true;
		}
		return false;
	}
	bool operator==(const S_2D路径顶点索引& other) const {
		if (p == other.p && 层 == other.层) {
			return other.idName == idName;
		}
		return false;
	}
	void f_setHash(uint64 val) {
		idName = std::hash<uint64>()(p * (层+1) | val);
	}
};

struct S_2D路径层 {
	std::list<std::list<S_2D路径顶点索引>>	index;
	std::vector<vec2>						point;
	std::vector<E_PathType2D>				inOut;
};

struct S_2D线段路径 {
	std::vector<std::vector<uvec2>>	index;
	std::vector<vec2>				point;
};

struct S_2D三角形 {
	std::vector<vec2>	point;
	std::vector<uint32>	index;
};


using t_2D顶点索引迭代器 = std::list<S_2D路径顶点索引>::iterator;

struct S_2D三角形迭代器 {
	t_2D顶点索引迭代器 ix;
	t_2D顶点索引迭代器 iy;
	t_2D顶点索引迭代器 iz;

	operator uvec3 () const {
		return {ix->p, iy->p, iz->p};
	}
};




struct S_3D路径层 {
	std::list<std::list<S_2D路径顶点索引>>	index;
	std::vector<vec3>						point;
};





//三角形中心点坐标
inline void f_三角形中心坐标(float 中心点坐标[3], const float PointA[3], const float PointB[3], const float PointC[3]) {
	中心点坐标[0] = (PointA[0] + PointB[0] + PointC[0]) / 3;
	中心点坐标[1] = (PointA[1] + PointB[1] + PointC[1]) / 3;
	中心点坐标[2] = (PointA[2] + PointB[2] + PointC[2]) / 3;
}

inline vec3 f_三角形中心坐标(const vec3& PointA, const vec3& PointB, const vec3& PointC) {
	return (PointA + PointB + PointC) / 3;
	return { (PointA.x + PointB.x + PointC.x) / 3.0f,
				(PointA.y + PointB.y + PointC.y) / 3.0f,
				(PointA.z + PointB.z + PointC.z) / 3.0f
	};
}

Inline vec2 f_graph_三角形中心(const vec2& PointA, const vec2& PointB, const vec2& PointC) {
	return (PointA + PointB + PointC) * 0.333333333333334;
}

Inline uvec3 f_geometry_TriangleIndex(uint32 offset, uint32 num) {
	uvec3 index = { offset, offset + 1, offset + 2 };
	index.y >= num ? index.y -= num : 0;
	index.z >= num ? index.z -= num : 0;
	return index;
}

//两线段距离


//三角形外切圆半径
inline float f_graph_三角形外切圆半径(const float PointA[3], const float PointB[3], const float PointC[3]) {
	float vec0[3] = { PointB[0] - PointA[0], PointB[1] - PointA[1], PointB[2] - PointA[2] };
	float vec1[3] = { PointC[0] - PointA[0], PointC[1] - PointA[1], PointC[2] - PointA[2] };
	float ABLen = vec_归一化(vec0);
	vec_归一化(vec1);
	float dot = vec_dot(vec0, vec1);
	//得出垂直边长度
	float AC = ABLen * dot;

	return (AC / dot) / 2;
}

Inline float f_graph_三角形外切圆半径(const vec2 PointA, const vec2 PointB, const vec2 PointC) {
	float32 a = length(PointA - PointB);
	float32 b = length(PointB - PointC);
	float32 c = length(PointC - PointA);
	//float32 s = (a+b+c) * 0.5;
	float32 area = 0.5 * fabs(PointA.x * (PointB.y - PointC.y) + PointB.x * (PointC.y - PointA.y) + PointC.x * (PointA.y - PointB.y));
	return (a*b*c) / (4*area);
}

Inline vec2 f_graph_三角形外切圆中心(const vec2 PointA, const vec2 PointB, const vec2 PointC) {
	float32 d = 2 * (PointA.x * (PointB.y - PointC.y) + PointB.x * (PointC.y - PointA.y) + PointC.x * (PointA.y - PointB.y));

	float32 ux = ((PointA.x * PointA.x + PointA.y * PointA.y) * (PointB.y - PointC.y) + 
				 (PointB.x * PointB.x + PointB.y * PointB.y) * (PointC.y - PointA.y) + 
				 (PointC.x * PointC.x + PointC.y * PointC.y) * (PointA.y - PointB.y)) / d;

	float32 uy = ((PointA.x * PointA.x + PointA.y * PointA.y) * (PointC.x - PointB.x) + 
				 (PointB.x * PointB.x + PointB.y * PointB.y) * (PointA.x - PointC.x) + 
				 (PointC.x * PointC.x + PointC.y * PointC.y) * (PointB.x - PointA.x)) / d;
	return {ux, uy};
}

Inline float32 f_graph_三角形外切圆半径(const vec2 center, const vec2 PointA, const vec2 PointB, const vec2 PointC) {
	float32 ABLen = vec_disSquar(center, PointA) + vec_disSquar(center, PointB) + vec_disSquar(center, PointC);
	return sqrt( ABLen / 3 );
}




//点到平面的距离
inline float f_点到平面距离(const float PointA[3], const float PointB[3], const float PointC[3], const float OutSidePoint[3]) {
	float vecAB[3] = { PointB[0] - PointA[0], PointB[1] - PointA[1], PointB[2] - PointA[2] };
	float vecAC[3] = { PointC[0] - PointA[0], PointC[1] - PointA[1], PointC[2] - PointA[2] };
	float vecPointToPlane[3] = { OutSidePoint[0] - PointA[0], OutSidePoint[1] - PointA[1], OutSidePoint[2] - PointA[2] };

	vec_归一化(vecAB);
	vec_归一化(vecAC);
	vec_归一化(vecPointToPlane);
	//计算平面法线
	float pn[3] = { 0.0,1.0,0.0 };
	vec_叉积(vecAB, vecAC, pn);

	//得到点和平面的距离
	return vec_dot(pn, vecPointToPlane) / 向量_两向量距离(pn);
}


inline float f_点到平面法线(const float PointA[3], const float PointB[3], const float PointC[3],
	const float OutSidePoint[3], float PNormal[3]) {

	float vecAB[3] = { PointB[0] - PointA[0], PointB[1] - PointA[1], PointB[2] - PointA[2] };
	float vecAC[3] = { PointC[0] - PointA[0], PointC[1] - PointA[1], PointC[2] - PointA[2] };
	float vecPointToPlane[3] = { OutSidePoint[0] - PointA[0], OutSidePoint[1] - PointA[1], OutSidePoint[2] - PointA[2] };

	vec_归一化(vecAB);
	vec_归一化(vecAC);
	//vec_normalize(vecPointToPlane);
	//计算平面法线
	vec_叉积(vecAB, vecAC, PNormal);
	float dis = vec_归一化(PNormal);

	//得到点和平面的距离
	return vec_dot(vecPointToPlane, PNormal) / dis;
}


//绕点旋转
inline void f_绕点旋转(const float point[3], const float dir, const float angle[3], float pos[3]) {
	float mat[16] = { 0.0 };
	Matrix4X4f_Identity(mat);
	float tranform[3] = { 0, 0.0, dir };

	Matrix4X4_Location(mat, tranform);
	Matrix4X4_Rotation(mat, angle);

	Matrix4X4_TranformVec(pos, point, mat);
}


inline float VecHamilton(const float vec[3], const float point[3], const float oper) {
	return (oper*vec[0]) / (oper*point[0]) + (oper*vec[1]) / (oper*point[1]) + (oper*vec[2]) / (oper*point[2]);
}



//取三角形AB边
inline float geometry_getTriangleEdgeAB(const S_三角形_& triangle, float vecAB[3]){
	vecAB[0] = triangle.pointB.x - triangle.pointA.x;
	vecAB[1] = triangle.pointB.y - triangle.pointA.y;
	vecAB[2] = triangle.pointB.z - triangle.pointA.z;

	return vec_归一化(vecAB);
}

//取三角形BC边
inline float geometry_getTriangleEdgeBC(const S_三角形_& triangle, float vecBC[3]){
	vecBC[0] = triangle.pointC.x - triangle.pointB.x;
	vecBC[1] = triangle.pointC.y - triangle.pointB.y;
	vecBC[2] = triangle.pointC.z - triangle.pointB.z;

	return vec_归一化(vecBC);
}

//取三角形AC边
inline float geometry_getTriangleEdgeAC(const S_三角形_& triangle, float vecAC[3]){
	vecAC[0] = triangle.pointC.x - triangle.pointA.x;
	vecAC[1] = triangle.pointC.y - triangle.pointA.y;
	vecAC[2] = triangle.pointC.z - triangle.pointA.z;

	return vec_归一化(vecAC);
}


//取三角形内点
inline void geometry_GetTriangleInsidePoint(const float vecAB[3], const float vecBC[3], const float spacing[2], float point[3]){
	point[0] = vecAB[0]*spacing[0] + vecBC[0]*spacing[1];
	point[1] = vecAB[1]*spacing[0] + vecBC[1]*spacing[1];
	point[2] = vecAB[2]*spacing[0] + vecBC[2]*spacing[1];
}

inline void geometry_GetTriangleInsidePoint(const S_三角形_ triangle, const float spacing[2], float point[3]){
	float vecAB[3] = {triangle.pointB.x-triangle.pointA.x
			  ,triangle.pointB.y-triangle.pointA.y
			  ,triangle.pointB.z-triangle.pointA.z};
	float vecAC[3] = {triangle.pointC.x-triangle.pointA.x
			  ,triangle.pointC.y-triangle.pointA.y
			  ,triangle.pointC.z-triangle.pointA.z};


}


//计算法线
inline void geometry_TriangleNormal(const S_三角形_ triangle, float normal[3]){
	float vecAB[3] = {0.0,0.0,0.0};
	float vecAC[3] = {0.0,0.0,0.0};
	geometry_getTriangleEdgeAB(triangle, vecAB);
	geometry_getTriangleEdgeAC(triangle, vecAC);

	vec_归一化(vecAB);
	vec_归一化(vecAC);
	vec_叉积(vecAB, vecAC, normal);
	vec_归一化(normal);
}

inline void geometry_TriangleNormal(const float pointA[3], const float pointB[3], const float pointC[3], float normal[3]){
	float vecAB[3] = {0.0,0.0,0.0};
	float vecAC[3] = {0.0,0.0,0.0};

	vecAB[0] = pointB[0]-pointA[0];
	vecAB[1] = pointB[1]-pointA[1];
	vecAB[2] = pointB[2]-pointA[2];

	vecAC[0] = pointC[0]-pointA[0];
	vecAC[1] = pointC[1]-pointA[1];
	vecAC[2] = pointC[2]-pointA[2];

	//Vec_normalize(vecAB);
	//Vec_normalize(vecAC);
	vec_叉积(vecAB, vecAC, normal);
	vec_归一化(normal);
}

inline vec3 f_geometry_TriangleNormal(const vec3 v0, const vec3 v1, const vec3 v2){
	vec3 normal = vec_cross(v1 - v0, v2 - v1);
	return normalize(normal);
}


inline float f_点到平面距离(const S_三角形_& triangle, const float OutSidePoint[3], float PNormal[3]){
	float vecAB[3] = {0.0,0.0,0.0};
	float vecAC[3] = {0.0,0.0,0.0};
	geometry_getTriangleEdgeAB(triangle, vecAB);
	geometry_getTriangleEdgeAC(triangle, vecAC);
	//float vecAB[3] = {PointB[0] - PointA[0], PointB[1] - PointA[1], PointB[2] - PointA[2]};
	//float vecAC[3] = {PointC[0] - PointA[0], PointC[1] - PointA[1], PointC[2] - PointA[2]};
	float vecPointToPlane[3] =
	{OutSidePoint[0] - triangle.pointA.x, OutSidePoint[1] - triangle.pointA.y, OutSidePoint[2] - triangle.pointA.z};

	vec_归一化(vecAB);
	vec_归一化(vecAC);
	//计算平面法线
	vec_叉积(vecAB, vecAC, PNormal);
	float dis = vec_归一化(PNormal);


	//得到点和平面的距离
	return vec_dot(vecPointToPlane, PNormal) / dis;
}

//沿法线移动
inline void triangl_normalMove(S_三角形_ triangle, const float dis){
	float vecAB[3] = {0.0,0.0,0.0};
	float vecAC[3] = {0.0,0.0,0.0};
	geometry_getTriangleEdgeAB(triangle, vecAB);
	geometry_getTriangleEdgeAC(triangle, vecAC);

	vec_归一化(vecAB);
	vec_归一化(vecAC);

	//计算平面法线
	float PNormal[3];
	vec_叉积(vecAB, vecAC, PNormal);
	vec_归一化(PNormal);
	vec_自乘(PNormal, dis);

	vec_自加((float32*)&triangle.pointA, PNormal);
	vec_自加((float32*)&triangle.pointB, PNormal);
	vec_自加((float32*)&triangle.pointC, PNormal);


}















//#endif // TRIANGLEGEOMETRY

/*inline float f_两线段距离(const float* vec0, const float* vec1) {
	float normal[3] = { 0.0, 0.0, 0.0 };
	vec_叉积(normal, vec0, vec1);
	float dot = vec_dot(vec0, vec1);
	return dot / 向量_两向量距离(normal);
}*/